home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 4 / ETO Development Tools 4.iso / Essentials / MacApp Documentation / MacApp.TECH$ Archives / 1989 / Nov 89 / 0054-More on USES (long)-Nov89 < prev    next >
Encoding:
Text File  |  1991-03-06  |  5.3 KB  |  140 lines  |  [TEXT/GEOL]

  1. Item forwarded  by  A33          to A34
  2.  
  3. Item    0755410                         7-Nov-89        15:03
  4.  
  5. From:   JOAQUIN1                        Joaquin, James
  6.  
  7. To:     ATTACHMATE                      Attachmate, John Bartleson,PRT
  8.  
  9. cc:     BURBECK.S                       Burbeck, Steve
  10.         MACAPP.TECH$                    MacApp Technical
  11.  
  12. Sub:    More on USES (long)
  13.  
  14. > If you have cycles, you have problems.  Of course, this ruins one of the best
  15. > aspects (in my opinion) of OOL, namely systems are composed of interacting
  16. > objects which can be arranged arbitrarily.  With Object Pascal, you must
  17. > impose some structure on these interactions.
  18.  
  19. I agree.  The development of modular, reusable code units is absolutely
  20. essential to successful large scale software development. Unfortunately, Object
  21. Pascal and its USES constraints present a major hurdle in implementing a
  22. modular design.  The fact that fields of an object must be declared in the
  23. interface of a unit almost guarantees circular USES references when one tries
  24. to create objects that are composed of, or descendents of, objects in other
  25. units.
  26.  
  27. The strategy that my group has adopted works as follows:
  28. Suppose you are creating a UNIT called MyView.  This unit defines one object
  29. called TMyView and is comprised of two files, UMyView.p (interface) and
  30. UMyView.inc1.p (implementation).
  31.  
  32. •The interface file (UMyView.p) would contain:
  33.    TMyView = OBJECT(TView)
  34.     fMyViewH:   Handle;
  35.     {-------------------field methods-------------------}
  36.     PROCEDURE TMyView.SetIntField(theInt: Integer);
  37.     FUNCTION TMyView.GetIntField : Integer;
  38.     PROCEDURE TMyView.SetCustomButton(theCustomButton: TControl);
  39.     FUNCTION TMyView.GetCustomButton : TControl;
  40.     {----------------other methods here-----------------}
  41.     PROCEDURE TMyView.Fields
  42.     etc...
  43.  
  44. •The implementation file (UMyView.inc1.p) would contain:
  45.    MyViewInfoType = RECORD
  46.     fIntField: INTEGER;
  47.     fCustomButton: TControl;
  48.    END; {MyViewInfoType}
  49.    MyViewInfoPtr = ^MyViewInfoType;
  50.    MyViewInfoH = ^MyViewInfoPtr;
  51.  
  52. PROCEDURE TMyView.SetIntField(theInt: Integer);
  53. BEGIN
  54.     MyViewInfoH(fMyViewH)^^.fIntField := theInt;
  55. END;
  56.  
  57. FUNCTION TMyView.GetIntField : Integer;
  58. BEGIN
  59.     GetIntField := MyViewInfoH(fMyViewH)^^.fIntField;
  60. END;
  61.  
  62. PROCEDURE TMyView.SetCustomButton(theCustomButton: TControl);
  63. BEGIN
  64.     {$IFC qDebug}
  65.     IF NOT Member(theCustomButton, TCustomButton) THEN
  66.         ProgramBreak('You must call SetCustomButton with a TCustomButton');
  67.     {$ENDC}
  68.     MyViewInfoH(fMyViewH)^^.fCustomButton := theCustomButton;
  69. END;
  70.  
  71. FUNCTION TMyView.GetCustomButton : TControl;
  72. BEGIN
  73.     GetCustomButton := MyViewInfoH(fMyViewH)^^.fCustomButton;
  74. END;
  75.  
  76. PROCEDURE TMyView.Fields(PROCEDURE DoToField(  fieldName: Str255;
  77.           fieldAddr: Ptr; fieldType: INTEGER)); OVERRIDE;
  78. VAR
  79.     temp:  MyViewInfoType;
  80.  
  81. BEGIN
  82.     temp := MyViewInfoH(fMyViewH)^^;
  83.     WITH temp DO
  84.     BEGIN
  85.         DoToField('fIntField',      @fIntField,     bInteger);
  86.         DoToField('fCustomButton',  @fCustomButton, bObject);
  87.     END; {WITH}
  88.     INHERITED Fields(DoToField);
  89. END;
  90.  
  91. Notice here we get inspection of fields just as if they were defined publicly
  92. with the object.  Also note that the fCustomButton is really an instance of
  93. TCustomButton (where TCustomButton is an object defined in UCustomButton which
  94. descends from TControl), even though our Get and Set methods use its nearest
  95. MacApp ancestor, TControl.
  96.  
  97. The burden is on the programmer to CAST to and from TCustomButton when calling
  98. Get & Set, i.e.
  99. aCustomButton: TCustomButton;
  100. ...
  101. New(aCustomButton);
  102. SELF.SetCustomButton(TControl(aCustomButton);
  103. ---- OR --------
  104. aCustomButton := TCustomButton(SELF.GetCustomButton);
  105. ...
  106.  
  107. I've found in many cases, especially when dealing with descendents of TView,
  108. one only needs to call methods of the MacApp ancestor class and can then call a
  109. Get method and assign it to a local var of type TView (or TControl, etc)
  110. without any casting.  Method calls of the ancestor can then be made without the
  111. code ever explicitly referring to the descendent class.
  112.  
  113. There are several PROS to this technique:
  114. 1) Since TMyView is composed of a TCustomButton it must include UCustomButton
  115. in its USES list, but NO OTHER UNIT using UMyView is required to use
  116. UCustomButton since it is explicitly referred to ONLY in the implementation.
  117. This has proved to be a HUGE gain when dealing with lots and lots of units and
  118. has allowed us to keep them small and modular.
  119. 2) Since the only field in TMyView is a handle to a private data structure,
  120. field assignment is bottlenecked through one SET method.  If the behavior of
  121. SetIntField needed to be enhanced (to do some range checking, perhaps), new
  122. code would only need to be added to SetIntField and UMyView would be the only
  123. unit needing recompilation.
  124. 3) Having a predefined RECORD containing all the data that describes an object
  125. can be very useful when storing to a file and restoring from a file.
  126.  
  127. Of course, there are also CONS:
  128. 1) Casting to and from the ancestor class adds work and potential confusion for
  129. the programmer.
  130. 2) There is obviously additional CPU overhead to call the Gets and Sets.
  131. 3) A fields record must be explicitly created for an object by the programmer,
  132. and must also be explicitly free'd by the programmer.
  133.  
  134. The pros of this technique have definitely outweighed the cons for us!
  135.  
  136. Hope this helps,
  137. James Joaquin
  138. Apple Computer
  139.  
  140.